#ifdef __X2LIB_WIN32__

#include "ProcPiper.h"
#include "DbgUtil.h"

using namespace x2lib;

uint8_t ProcPiper::TRANCODE[16] = { 0x58, 0x82, 0x31, 0x1C, 0x8F, 0x49, 0x49, 0xB6, 0xBB, 0x20, 0x3E, 0x3C, 0xF4, 0xE7, 0x80, 0xAA };

ProcPiper::ProcPiper(bool isClient, ProcPiper::Listener *pListener) :
	Transceiver(isClient, ProcPiper::TRANCODE, 1024 * 32),
	m_pListener(pListener),
	m_hEvtAccept(NULL)
{
	m_hEvtSend = CreateEvent(NULL, TRUE, FALSE, NULL);
	m_hEvtRecv = CreateEvent(NULL, TRUE, FALSE, NULL);
}

ProcPiper::~ProcPiper()
{
	CloseHandle(m_hEvtSend);
	CloseHandle(m_hEvtRecv);
}

bool ProcPiper::Execute(const char* pszName, int reConnWaitsec, int reConnTimes)
{
	strcpy(m_szName, pszName);
	return Transceiver::Execute(reConnWaitsec, reConnTimes);
}

void ProcPiper::Exit()
{
	if (m_hEvtAccept) { SetEvent(m_hEvtAccept); }
	Transceiver::UnInit();
}

int ProcPiper::ApiSend(AbsChannel* pChannel, void* pData, uint32_t nData, uint32_t* pnBytes)
{
#if 0 // 同步操作，要求handle为同步类型
	BOOL bRet = WriteFile(pChannel->handle, pData, nData, (DWORD*)pnBytes, NULL);
	if ((!bRet || nData != *pnBytes) && (pChannel->handle != INVALID_HANDLE_VALUE))
	{ // 判为意外断开！！！
		return 0;
	}
#else // 异步操作，要求handle为异步类型
	// 简单处理
	OVERLAPPED overLapped = { 0 };
	overLapped.hEvent = NULL; // CreateEvent(NULL, TRUE, FALSE, NULL);
	*pnBytes = nData; // 假设写入的都能成功传输
	BOOL bRet = WriteFile((HANDLE)pChannel->handle, pData, nData, NULL, &overLapped);
	//CloseHandle(overLapped.hEvent);
	if ((!bRet && ERROR_IO_PENDING != GetLastError()) && ((HANDLE)pChannel->handle != INVALID_HANDLE_VALUE))
	{ // 判为意外断开！！！
		return 0;
	}
#endif
	return 1;
}

bool ProcPiper::ApiRecv(AbsChannel* pChannel, void* pData, uint32_t nData, uint32_t* pnBytes)
{
	bool isSucc = true;

#if 0 // 同步操作，要求handle为同步类型
	if (PeekNamedPipe(pChannel->handle, pData, nData, (DWORD*)pnBytes, NULL, NULL) && (*pnBytes) > 0)
	{
		ReadFile(pChannel->handle, pData, nData, (DWORD*)pnBytes, NULL);
	}
	else
	{
		if (GetLastError() == ERROR_BROKEN_PIPE)
		{ // 判为意外断开！！！
			SetLastError(0);
			isSucc = false;
		}
	}
#else // 异步操作，要求handle为异步类型，有待优化
	// 简单处理
	OVERLAPPED overLapped = { 0 };
	overLapped.hEvent = m_hEvtRecv;
	ResetEvent(m_hEvtRecv);
	BOOL bRet = ReadFile((HANDLE)pChannel->handle, pData, nData, NULL, &overLapped);
	if (!bRet && ERROR_IO_PENDING != GetLastError() && ERROR_NO_DATA != GetLastError()/* && STATUS_PENDING != overLapped.Internal*/)
	{
		SetLastError(0);
		isSucc = false;
	}
	else
	{ // 其他情况不视为断开连接，可能包括：等待超时，无数据等
		if (WAIT_OBJECT_0 == WaitForSingleObject(overLapped.hEvent, 50))
		{
			// pnBytes貌似返回的是还有多少已传输的数据未被ReadFile获取
			if (GetOverlappedResult((HANDLE)pChannel->handle, &overLapped, (DWORD*)pnBytes, FALSE))
			{
				//ReadFile(pChannel->handle, pData, nData, NULL, &overLapped);
				//*pnBytes = overLapped.InternalHigh;
			}
		}
	}
#endif

	return isSucc;
}

Transceiver::AbsChannel* ProcPiper::connectServer(bool isReConn)
{
	if (!WaitNamedPipeA((LPCSTR)m_szName, NMPWAIT_WAIT_FOREVER)) { return nullptr; }

	HANDLE hPipe = CreateFileA((LPCSTR)m_szName, GENERIC_READ | GENERIC_WRITE, 0, NULL, CREATE_NEW, FILE_FLAG_OVERLAPPED, NULL);
	if (hPipe == INVALID_HANDLE_VALUE) { return nullptr; }

	Channel* pChannel = new Channel();
	pChannel->handle = (intz_t)hPipe;
	return pChannel;
}

Transceiver::AbsChannel* ProcPiper::acceptClients()
{
	Channel* pChannel = nullptr;
	do
	{
#if 1
		HANDLE hPipe = CreateNamedPipeA((LPCSTR)m_szName, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED/*重叠IO*/,
			PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, 0, 0, 0, NULL);
		if (hPipe == INVALID_HANDLE_VALUE) { break; }

		m_hEvtAccept = CreateEvent(NULL, TRUE, TRUE, NULL);
		OVERLAPPED overLapped = { 0 };
		overLapped.hEvent = m_hEvtAccept;

		// 使用overLapped切换为异步模式【需结合Event】
		ConnectNamedPipe(hPipe, &overLapped);/* && GetLastError() != ERROR_PIPE_CONNECTED*/ //)
		WaitForSingleObject(overLapped.hEvent, INFINITE);
		CloseHandle(m_hEvtAccept);
		m_hEvtAccept = NULL;
		DWORD dwBytesTransferred = 0;
		if (!GetOverlappedResult(hPipe, &overLapped, &dwBytesTransferred, FALSE))
		{
			FlushFileBuffers(hPipe);
			CloseHandle(hPipe);
			break;
		}
#else
		HANDLE hPipe = CreateNamedPipeA((LPCSTR)pThis->m_szName, PIPE_ACCESS_DUPLEX,
			PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_NOWAIT, PIPE_UNLIMITED_INSTANCES, 0, 0, 0, NULL);

		// 1.如果WaitNamedPipe先于ConnectNamedPipe执行，则该函数立即返回并GetLastError==ERROR_PIPE_CONNECTED
		// 2.如果WaitNamedPipe后于ConnectNamedPipe执行，则该函数阻塞直到WaitNamedPipe调用后，他返回非0。
		if (hPipe == INVALID_HANDLE_VALUE || (!ConnectNamedPipe(hPipe, NULL) && GetLastError() != ERROR_PIPE_CONNECTED))
		{
			FlushFileBuffers(hPipe);
			CloseHandle(hPipe);
			Sleep(1000);
			continue;
		}
#endif

		DWORD dwNewMode = PIPE_READMODE_BYTE | PIPE_NOWAIT; // set for ReadFile/WriteFile change to unblocking-mode
		SetNamedPipeHandleState(hPipe, &dwNewMode, NULL, NULL);

		pChannel = new Channel();
		pChannel->handle = (intz_t)hPipe;
	} while (false);

	return pChannel;
}

void ProcPiper::closeChannel(AbsChannel* pChannel)
{
	// 关闭，删除管道
	FlushFileBuffers((HANDLE)pChannel->handle);
	if (m_isClient)
	{
		DisconnectNamedPipe((HANDLE)pChannel->handle);
	}
	CloseHandle((HANDLE)pChannel->handle);
	delete pChannel;
}

void ProcPiper::OnConnected(AbsChannel* pChannel)
{
	m_pListener->OnPipeConn((Channel*)pChannel);
}

void ProcPiper::OnPackRecved(AbsChannel* pChannel)
{
	// int nTran = pTranPack->Head.iSeek + pTranPack->Head.nBytes - TranPack::MIN;
	// LOG_PRINT_I("OnPackRecved %.1f%%%%(%d/%d)\n", 100.0f * nTran / pTranPack->Head.nTotal, nTran, pTranPack->Head.nTotal);

	// m_pListener->OnPipeRecv((Channel*)pChannel, pData, nData);
}

#endif
